package com.sky.module.security.filter;

import com.sky.config.redis.RedisService;
import com.sky.module.security.exception.CustomerAuthenticationException;
import com.sky.module.security.handler.LoginFailureHandler;
import com.sky.module.security.service.CustomUseDetailService;
import com.sky.module.suppot.file.s3.OssProperties;
import com.sky.module.system.permission.domain.entity.Permission;
import com.sky.module.system.utils.JwtUtils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/***
 * @description 检查token过滤器
 * @param null
 * @return
 * @date 2023/2/20 13:08
 *
 */
@Data
@Component
public class CheckTokenFilter extends OncePerRequestFilter {

    @Value("${request.login.url}")
    private String loginUrl;

    @Autowired
    private JwtUtils jwtUtils;

    @Resource
    private RedisService redisService;

    @Autowired
    private CustomUseDetailService customUseDetailService;

    @Resource

    private LoginFailureHandler loginFailureHandler;


    @Resource
    private OssProperties ossProperties;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
//            获取当前当前请求url
            String url = request.getRequestURI();
            final Map<String, String[]> map = request.getParameterMap();
            map.forEach((k, v) -> {
                System.out.println("k = " + k);
                for (String s : v) {
                    System.out.println("s = " + s);
                }
            });
//        判断当前请求是否是登录请求，如果不是，则需要校验token
            // 本地存储图片预览 sky
            if (!url.equals(loginUrl) && !url.contains("/sky") && !url.contains("/favicon.ico")
                    && !url.contains("/test/")) {
                this.valiataToken(request);
            }
        } catch (AuthenticationException e) {
            // token校验失败
            loginFailureHandler.onAuthenticationFailure(request, response, e);
        }
//        登录请求不需要携带token，可以直接放行
        filterChain.doFilter(request, response);
    }

    /***
     * @description 验证token信息
     * @param request
     * @return void
     * @date 2023/2/20 14:30
     *
     */
    private void valiataToken(HttpServletRequest request) throws CustomerAuthenticationException {
//            获取从前端提交的token信息
//            从headers 头部获取token信息

        String token = request.getHeader("token");
//        如果请求头部没有携带token，则从请求的参数中获取
        if (ObjectUtils.isEmpty(token)) {
            token = request.getParameter("token"); // 从参数中获取
        }
        if (ObjectUtils.isEmpty(token)) {
            throw new CustomerAuthenticationException("没有携带token");

//        如果请求参数中也没有携带token信息就抛出异常
        }
//        查看redis中是否存在token
        String tokenKey = "token_" + token;
        String redisToken = redisService.get(tokenKey);
//        判断redis中是否存在token信息 如果为空表示token已经失效
        if (ObjectUtils.isEmpty(redisToken)) {
            throw new CustomerAuthenticationException("token验证失败");
        }
        // 如果存在token就解析
//        if (!token.equals(redisToken)) {
//            throw new CustomerAuthenticationException("token验证失败");
//
//        }
//        如果token 存在 从token 中解析出用户名
        String username = jwtUtils.getUsernameFromToken(redisToken);
        if (StringUtils.isEmpty(username)) {
            throw new CustomerAuthenticationException("token里的用户名为空");

        }
//        获取用户信息

        final UserDetails userDetails = customUseDetailService.loadUserByUsername(username);
//        判断用户信息是否为空
        if (userDetails == null) {
            throw new CustomerAuthenticationException("用户信息为空");

        }
//        创建用户身份认证对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                userDetails, null, userDetails.getAuthorities()
        );
//        设置请求信息
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
//        将验证的信息讲给SpringSecurity 上下文进行管理
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

    }
}
